from pygame.sprite import Sprite
from pygame.locals import *
import sys,traceback

import pygame
def _parseImages(source_img,tile_width,tile_height,spacing=0,margin=0):
    '''
    Parse a pygame surface (with the parts of a animation) into into separate surface parts 
    '''
    w, h = source_img.get_size()
    colorkey = source_img.get_colorkey()
    # unset the colorkey when we blit to separate images
    # otherwise it will be lost..
    source_img.set_colorkey(None)
    images = []
    for y in xrange(margin, h, tile_height + spacing):
        for x in xrange(margin, w, tile_width + spacing):
            img_part = pygame.Surface((tile_width, tile_height), 0, source_img)
            img_part.blit(source_img, (0, 0), pygame.Rect(x, y, tile_width, tile_height))
            if colorkey:
                img_part.set_colorkey(colorkey)
            img_part.convert()
            images.append(img_part)
            
    source_img.set_colorkey(colorkey)
    return images


class Animation(list):
    def __init__(self,source_img,tile_width,tile_height,fps,spacing=0,margin=0):
        list.__init__(self)
        self.extend(_parseImages(source_img,tile_width,tile_height,spacing=spacing,margin=margin))
        self.tile_width = tile_width
        self.tile_height = tile_height
        self.img_count = source_img.get_width()/tile_width
        self.fps = fps
        self.img_cnt = len(self)

    def getImage(self,time_,fps=None):
        if fps is None:
            fps = self.fps
        image_no = int((time_*fps)%self.img_cnt)
        return self[image_no]
    
    def __repr__(self):
        return 'Animation: tile size:%dx%d fps:%d length:%d'%(self.tile_width,self.tile_height,self.fps,self.img_cnt)
from math import hypot
def vel_limit(vx,vy,max_vel):
    v = hypot(vx,vy)
    if v > max_vel:
        d = max_vel/v
        vx = vx*d
        vy = vy*d
        return vx,vy
    return vx,vy


class GameObject(Sprite):
    ID = 0 # static 
    COLLIDE_TOP = 0x1
    COLLIDE_BOTTOM = 0x2
    COLLIDE_LEFT = 0x4
    COLLIDE_RIGHT = 0x8
    
    image=None

    collide_damage_ratio = 0.001 # game world map collision speed to damage ratio
    bounce_ratio = 0.6 # game world map collide bounce back  ratio
    
    def __init__(self,game_engine,pos_x,pos_y,vel_x=0,vel_y=0,image=None,id = None):
        Sprite.__init__(self) #call Sprite initializer        
        if image:
            self.image = image
        self.rect = self.image.get_rect()
        self.pos_x = pos_x
        self.pos_y = pos_y
        self.vel_x = vel_x
        self.vel_y = vel_y
        self.collide_dirs = 0
        self.game_engine = game_engine
        self.game_map = game_engine.game_map
        self.rect.center = (self.pos_x, self.pos_y)
        
        # give my self a uniqe gameobject ID
        if id != None:
            self.id = id    
        else:
            self.id = GameObject.ID    
            GameObject.ID += 1

    def reset(self):        
        self.vel_x = 0
        self.vel_y = 0

    def update(self,dt):
        pass

    def move(self,dt):
        self.old_pos_x,self.old_pos_y = self.pos_x,self.pos_y
        self.collide_limit()
        self.pos_x += self.vel_x*dt
        self.pos_y += self.vel_y*dt
        self.rect.center = (self.pos_x, self.pos_y)

    def collide_limit(self):
        if self.collide_dirs:
            c= self.collide_dirs
            if c & self.COLLIDE_TOP:
                self.vel_y = max(self.vel_y,0)
            if c & self.COLLIDE_BOTTOM:
                self.vel_y = min(self.vel_y,0)
            if c & self.COLLIDE_RIGHT:
                self.vel_x = max(self.vel_x,0)
            if c & self.COLLIDE_LEFT:
                self.vel_x = min(self.vel_x,0)

    def changeVel(self, x,y,dt):
        ''
        self.vel_x += x*dt
        self.vel_y += y*dt

    def decreaseVel(self, d,dt):
        'decrease velosity'
        if self.vel_x > 0:self.vel_x += -d*dt
        elif self.vel_x < 0:self.vel_x += d*dt
        if self.vel_y > 0:self.vel_y += -d*dt
        elif self.vel_y < 0:self.vel_y += d*dt

    def sync(self,sync_info):
        ' Sync myself with sync dict '
        self.pos_x = sync_info['pos_x']
        self.pos_y = sync_info['pos_y']
        self.vel_x = sync_info['vel_x']
        self.vel_y = sync_info['vel_y']


    def getSync(self):
        ' Return information about GameObject for syncing over net '
        return {'pos_x':self.pos_x,'pos_y':self.pos_y,'vel_x':self.vel_x,'vel_y':self.vel_y}

    def setVel(self,x,y):
        self.vel_x = x
        self.vel_y = y

class AnimatedGameObject(GameObject):
    def __init__(self,*args,**kwargs):
#        print self.animation
        self.image = self.animation[0] 
        GameObject.__init__(self,*args,**kwargs)
        self.time = 0.0
        
    def update(self,dt):
        super(GameObject,self).update(dt)
        if self.animation.fps:
            self.time += dt
            self.image = self.animation.getImage(self.time)
        